
import time
import traceback
from datetime import datetime

import orjson
import schedule

import settings
from src.db import task_op
from src.enum.exception import ExceptionEnum
from src.enum.task import CrawlerStatusEnum, CrawlerTypeEnum, ExecResultEnum
from src.exception import CrawlerException, CrawlerFailureException
from src import plugin
from src.model.air_waybill import AwbResult
from src.model.ocean_bill_of_lading import OblResult
from src.util import flogger, common_util

log = flogger.Flogger().get_logger(__name__)

# 定义一个函数来运行调度器
def boot_scheduler():
    while True:
        schedule.run_pending()
        time.sleep(1)

def scan_crawler_task():
    executable_status_list = [CrawlerStatusEnum.EXECUTING, CrawlerStatusEnum.ABNORMAL_DELAY]
    task_list = task_op.query_all_by_crawler_status(executable_status_list)

    for task in task_list:
        crawler_type_name = None
        crawler_number = None
        try:
            if task.crawler_times > 3:
                raise CrawlerFailureException(
                    exec_result=ExecResultEnum.EXECUTE_ABNORMAL_FAILURE,
                    error=ExceptionEnum.CRAWLER_TIMES_MORE_THAN_MAX_TIMES
                )
            task.crawler_times = task.crawler_times + 1
            task.exec_time = datetime.now()
            task.reason = None
            task.data_file_path = None
            if task.crawler_type == CrawlerTypeEnum.OCEAN_WAYBILL.value:
                params = orjson.loads(task.crawler_params)
                uni_code = params['uni_code']
                waybill_num = params['waybill_num']
                obl_spider: plugin.OblSpiderBase = plugin.load_plugin_class(CrawlerTypeEnum.OCEAN_WAYBILL, uni_code,
                                                                              "BillOfLadingSpider")
                result:OblResult = obl_spider.run(waybill_num)
                data_file_path = f"{settings.PATH_DATA_DIR}/obl/{uni_code}/{waybill_num}.data"
                crawler_type_name = CrawlerTypeEnum.OCEAN_WAYBILL.name
                crawler_number = f"{waybill_num}({uni_code})"
            elif task.crawler_type == CrawlerTypeEnum.AIR_WAYBILL.value:
                params = orjson.loads(task.crawler_params)
                uni_code = params['uni_code']
                awb_num = params['waybill_num']
                awb_spider: plugin.AwbSpiderBase = plugin.load_plugin_class(CrawlerTypeEnum.AIR_WAYBILL, uni_code,
                                                                              "AirWaybillSpider")
                result:AwbResult = awb_spider.run(awb_num)
                data_file_path = f"{settings.PATH_DATA_DIR}/awb/{uni_code}/{awb_num}.data"
                crawler_type_name = CrawlerTypeEnum.AIR_WAYBILL.name
                crawler_number = f"{awb_num}({uni_code})"
            else:
                raise CrawlerFailureException(
                    exec_result=ExecResultEnum.INIT,
                    error=ExceptionEnum.UNDEFINED_CRAWLER_TYPE_ERROR
                )
            if result is None:
                raise CrawlerFailureException(
                    exec_result=ExecResultEnum.NULL_DATA,
                    error=ExceptionEnum.CRAWLER_RESULT_NULL_ERROR
                )
            task.crawler_status = CrawlerStatusEnum.FINISH.value
            task.exec_result = ExecResultEnum.SUCCESS.value
            common_util.save_text_to_file(data_file_path,result.model_dump_json())
            task.data_file_path = data_file_path
            log.info(f"{crawler_type_name} crawler number: {crawler_number},crawler_id:{task.crawler_id} crawler data success!")
        except CrawlerException as e:
            log.info(
                f"{crawler_type_name} crawler number: {crawler_number},crawler_id:{task.crawler_id} crawler exception!")
            log.error(str(e))
            log.error(traceback.format_exc())
            task.crawler_status = e.crawler_status
            task.exec_result = e.exec_result
            task.reason = e.reason
        except Exception as e:
            log.info(
                f"{crawler_type_name} crawler number: {crawler_number},crawler_id:{task.crawler_id} crawler failure!")
            log.error(str(e))
            log.error(traceback.format_exc())
            task.crawler_status = CrawlerStatusEnum.FAILURE
            task.exec_result = ExecResultEnum.UNDEFINED_FAILURE
            task.reason = "[" + ExceptionEnum.UNKNOWN_ERROR.code + "]" +ExceptionEnum.UNKNOWN_ERROR.msg

        task_op.update(task=task)